/**
 * @description 接口采集-控制器
 * @since 2019-11-12
 * @author Rid King
*/

const ox = require('@daelui/oxjs')
const Service = require('./service.js')

class Controller extends ox.Controller {
  /**
   * @function 构造方法
  */
  constructor (args) {
    super(args)
    // 服务
    this.$service = new Service(args)
  }

  /**
   * @function 存储数据
   * @param {Object} action 操作集合
   * @demo
   * {
   *  req: {Request}
   *  res: {Response}
   * }
   * @return {Boolean/Error}
  */
  async store (action, extender) {
    // 解析数据
    return this.solveAction(action, extender).then(async action => {
      let res = await this.filterAction({ name: 'store', action })
      // 数据
      let list = action.groupInerList
      list = Array.isArray(list) ? list : []
      if (res && res.success) {
        let result = {}
        for (let i = 0; i < list.length; i++) {
          let inter = list[i]
          // 查询与当前path匹配的已有接口
          let res = await this.queryAll({}, {
            action: {},
            query: {},
            params: {
              name: inter.name,
              href: inter.href,
              url: inter.url,
              fileName: inter.fileName,
              lineNumber: inter.lineNumber,
              columnNumber: inter.columnNumber,
              message: inter.message,
              userAgent: inter.userAgent
            },
            excute: {
              operators: [
                { field: 'name', operator: 'EQUAL' },
                { field: 'href', operator: 'EQUAL' },
                { field: 'url', operator: 'EQUAL' },
                { field: 'fileName', operator: 'EQUAL' },
                { field: 'lineNumber', operator: 'EQUAL' },
                { field: 'columnNumber', operator: 'EQUAL' },
                { field: 'message', operator: 'EQUAL' },
                { field: 'userAgent', operator: 'EQUAL' }
              ],
              sort: [
                {field: 'updateTime', by: 'asc'}
              ]
            }
          })
          let inters = res.data
          inters = Array.isArray(inters) ? inters : []
          action.params = inter
          // 超过每个路径、每种状态存储上限的，按更新处理
          let statusMax = inter.statusMax
          statusMax = parseInt(statusMax)
          statusMax = isNaN(statusMax) ? 10 : statusMax
          statusMax = statusMax < 1 ? 1 : statusMax
          if (inters.length >= statusMax) {
            inter.id = inters[0].id
            result = await this.$service.update(action)
          } else {
            result = await this.$service.add(action)
          }
        }
        res = {data: result.data, success: result ? 1 : 0, msg: result.msg, code: result.code}
        this.emit('store', action, res)
      }
      return res
    })
  }

  /**
   * @function 增删改过滤
  */
  async filterAction ({ name, action }) {
    // 新增判断
    if (name === 'store') {
      let groups = []
      try {
        // 查询所有的分组数据
        let res = await this.$router.getControllInstance({path: '/tigerlair/collect/error/group'}).queryAll({}, {
          action: {},
          query: {},
          params: {},
          excute: {
            operators: [],
            sort: [
              {field: 'createTime', by: 'desc'},
              {field: 'order', by: 'desc'}
            ]
          }
        })
        let list = res.data
        list = Array.isArray(list) ? list : []
        groups = list
      } catch (e) {
        groups = []
      }
      // 无分组直接返回
      if (!groups.length) {
        return { success: 0, msg: 'No collect group' }
      }
      let result = await this.processGroup(groups, action)
      if (!result || !result.success) {
        return { success: 0, msg: 'No matched group' }
      }
      return { success: 1 }
    }
    return { success: 1 }
  }

  // 分组处理
  processGroup (groups, action) {
    groups = Array.isArray(groups) ? groups : []
    // 无效数据
    if (!groups || !groups.length) {
      return false
    }
    let params = action.params || []
    params = Array.isArray(params) ? params : [params]
    let groupInerList = [] // 根据分组生成的数据
    params = params.filter(req => {
      // 无效数据
      if (!req.name) {
        return false
      }
      // 分组是否匹配
      let isGroupMath = false
      // 遍历分组
      groups.forEach(group => {
        // 匹配规则
        let matchRules = group.matchRules
        if (/\[/.test(matchRules)) {
          try {
            matchRules = JSON.parse(matchRules)
          } catch (e) {
            matchRules = []
          }
        } else {
          matchRules = []
        }
        // 是否有规则匹配
        let isMatch = false, isAndMatch = true, orModes = [], andModes = []
        matchRules.forEach(rule => {
          // 进行规则判断的值
          let value = req[rule.matchField] || ''
          let b = false
          // 值与规则判断
          if (value === '' || value === null || value === undefined) {
            return true
          }
          value = String(value).toLowerCase()
          // 字符串匹配
          if (rule.matchType === 'string') {
            b = value.indexOf(String(rule.matchValue || '').toLowerCase()) > -1
          }
          // 正则
          else if (rule.matchType === 'regexp') {
            let regexp = this.toRegExp(rule.matchValue)
            if (typeof regexp === 'object') {
              b = regexp.test(value)
            }
          }
          // 函数
          else if (rule.matchType === 'function' && rule.matchCoderCompiled) {
            // 函数解析
            try {
              let matchCoder = this.compileModule(matchCoder)
              try {
                let res = matchCoder(value, req, rule)
                res = typeof res === 'boolean' ? res : true
                b = b && res
              } catch (e) {}
            } catch (e) {}
          }
          if (rule.matchMode === 'and') {
            andModes.push(1)
            isAndMatch = b && isAndMatch
          } else {
            orModes.push(1)
            isMatch = b || isMatch
          }
        })
        // 全部条件都是and则or为true
        if (!orModes.length && andModes.length) {
          isMatch = true
        }
        // 匹配判断不通过
        if (!(isMatch && isAndMatch)) {
          return false
        }

        // 基础转换
        req = { ...req }
        this.processRow(req, group)

        // 转换规则
        let transformRules = group.transformRules
        if (/\[/.test(transformRules)) {
          try {
            transformRules = JSON.parse(transformRules)
          } catch (e) {
            transformRules = []
          }
        } else {
          transformRules = []
        }
        // 处理方法转换
        transformRules.forEach(rule => {
          // 进行规则判断的值
          let value = req[rule.transformField] || ''
          // 值与规则判断
          if (value === '' || value === null || value === undefined) {
            return true
          }
          value = String(value)
          // 字符串匹配
          if (rule.transformType === 'string') {
            value = value.replace(rule.rule, rule.transformValue)
            req[rule.transformField] = value
          }
          // 正则
          else if (rule.transformType === 'regexp') {
            let regexp = this.toRegExp(rule.replace)
            if (typeof regexp === 'object') {
              value = value.replace(regexp, rule.transformValue)
              req[rule.transformField] = value
            }
          }
          // 函数
          else if (rule.transformType === 'function' && rule.transformCoderCompiled) {
            // 函数解析
            try {
              let transformCoder = this.compileModule(transformCoder)
              try {
                let result = transformCoder(req, rule)
                let type = typeof result
                req[rule.transformField] = type === 'string' || type === 'number' || type === 'boolean' ? result : req[rule.transformField]
              } catch (e) {}
            } catch (e) {}
          }
        })

        // 添加至分组数据
        groupInerList.push({
          ...req,
          gid: group.id,
          statusMax: group.statusMax
        })

        // 分组匹配完成
        isGroupMath = true
      })
      return isGroupMath
    })
    // 无效数据
    if (!params.length) {
      return false
    }
    action.groupInerList = groupInerList
    return { success: 1 }
  }

  /**
   * @function 数据处理
   * @param {Object} params
   * @return {Promise}
  */
  processRow (params, group) {
    this.lighten(params, group)
  }

  /**
   * @function 数据轻量化
   * @param {any} data 数据
  */
  lighten (data, group) {
    let type = Object.prototype.toString.call(data)
    let lightenMax = group.lightenMax
    lightenMax = parseInt(lightenMax)
    lightenMax = isNaN(lightenMax) ? 3 : lightenMax
    lightenMax = lightenMax > 100 ? 100 : lightenMax < 1 ? 1 : lightenMax
    let strMax = group.strMax
    strMax = parseInt(strMax)
    strMax = isNaN(strMax) ? 10000 : strMax
    strMax = strMax < 1 ? 0 : strMax
    strMax = strMax > 1000000 ? 1000000 : strMax < 1 ? 1 : strMax
    // 对象形式
    if(type === '[object Object]') {
      for (let key in data) {
        data[key] = this.lighten(data[key], group)
      }
    }
    // 数据形式
    else if(Array.isArray(data)){
      let list = []
      data.forEach((item, i)=>{
        if(i >= lightenMax) {
          return false
        }
        list.push(this.lighten(item, group))
      })
      data =list
    } else if (type === '[object String]') {
      let res = this.toObject(data)
      if (res && typeof res === 'object') {
        return this.lighten(res, group)
      } else {
        // 删除图片
        if (String(group.isClearImg) !== '0' || String(group.isClearImg) !== 'false') {
          data = data.replace(/<img\s+[^>]+>/mg, '')
        }
        // 最大字符限制
        if (data.length > strMax) {
          data = data.slice(0, strMax)
        }
      }
    }

    return data
  }

  // 函数转换
  compileModule(code, globals = {}) {
    const exports = {}
    const module = { exports }
    const globalNames = Object.keys(globals)
    const keys = ['module', 'exports', ...globalNames]
    const values = [module, exports, ...globalNames.map(key => globals[key])]
    let defaults = new Function(keys.join(), code)
    defaults.apply(exports, values)
    return module.exports
  }

  // 正则转换
  toRegExp (str) {
    let type = Object.prototype.toString.call(str)
    // 正则
    if (type === '[object RegExp]') {
      return str
    }
    if (type === '[object Number]' || type === '[object String]') {
      type = String(str)
      if (!/^\/.+\/$/.test(str)) {
        str = '/' + str + '/'
      }
      try {
        let reg = new Function('return ' + str)()
        if (Object.prototype.toString.call(reg) === '[object RegExp]') {
          return reg
        } else {
          return false
        }
      } catch (e) {
        return false
      }
    }
    return false
  }

  /**
   * @function 转换成对象
   * @param {Any} data 数据
   * @return {Any}
  */
  toObject (data) {
    let result = data
    if (typeof data === 'string' && /\{|\[/m.test(data)) {
      try {
        result = (new Function('return ' + data))()
      } catch (e) {
        result = data
      }
    }

    return result
  }

  /**
   * @function 转换成字符串
   * @param {Any} data 数据
   * @return {Any}
  */
  toString (data, a1, a2) {
    let result = data
    if (data && typeof data === 'object') {
      try {
        result = JSON.stringify(data, a1, a2)
      } catch (e) {
        result = data
      }
    }

    return result
  }

  /**
   * @function sass服务
   * @param {Any} data 数据
   * @return {Any}
  */
  sass (action, extender) {
    // 解析数据
    return this.solveAction(action, extender).then(async action => {
      let inter = action.params || {}
      let res = { data: [] }
      // 查询与当前path匹配的已有接口
      if (inter.i || inter.u) {
        res = await this.queryAll({}, {
          action: {},
          query: {},
          params: {
            id: inter.i,
            path: inter.u,
            method: String(inter.m || action.req.method || 'get').toLowerCase(),
            status: '200'
          },
          excute: {
            operators: [
              { field: 'id', operator: 'EQUAL', toLowerCase: true },
              { field: 'path', operator: 'EQUAL', toLowerCase: true },
              { field: 'method', operator: 'LIKE' },
              { field: 'status', operator: 'EQUAL' }
            ],
            sort: [
              {field: 'createTime', by: 'desc'},
              {field: 'order', by: 'desc'}
            ]
          }
        })
      }
      let inters = res.data
      inters = Array.isArray(inters) ? inters : []
      let key = inter.c === 'request' ? 'request' : 'response'
      let result = (inters[0] || {})[key]
      result = this.toObject(result || {})
      if (inter.f === 'json') {
        result = this.toString(result, null, ' ')
      }
      return { type: 'PLAINTEXT', data: result }
    })
  }
}

module.exports = Controller